assume cs:code,ss:stackmg

data segment   ; 设置可容纳1300条信息
    data_start db   62400 dup(?)  ;48 * 1300   ;;; db 'A',46 dup(0),77,'B',46 dup(0),88,'C',46 dup(0),99,'D',46 dup(0),44   ;;;      
                 
  
data ends

pointers segment
    pointers_start     dw 1300 dup(?)  ;1 * 1000     ;;;    dw 0,48,96,144  
pointers ends

;================================================================
; 其它函数
mov_dssi_to_cache_area macro
; 设置ds:si为缓存区地址
    push ax
    mov ax,cache_area
    mov ds,ax
    lea si,cache_area_start
    pop ax
endm

;================================================================
mov_esdi_to_cache_area macro
; 设置ds:si为缓存区地址
    push ax
    mov ax,cache_area
    mov es,ax
    lea di,cache_area_start
    pop ax
endm

;================================================================
mov_dssi_to_cache_area2 macro
; 设置ds:si为缓存区2地址
    push ax
    mov ax,cache_area2
    mov ds,ax
    lea si,cache_area_start2
    pop ax
endm

;================================================================
mov_esdi_to_cache_area2 macro
; 设置ds:si为缓存区2地址
    push ax
    mov ax,cache_area2
    mov es,ax
    lea di,cache_area_start2
    pop ax
endm




;================================================================

copy_from_es_to_ds macro times
; 从ex复制数据到ds times次
    push cx
    pushf
    mov cx,times
    cld
    rep movsb
    popf
    pop cx
endm
;================================================================



clear_area_data SEGMENT
    _1 dw 1
    _2 dw 2
    _3 dw 3
    _8 dw 8
    _12 dw 12
    _16 dw 16
    _24 dw 24
    _48 dw 48
    _80 dw 80
clear_area_data ends
;================================================================

clear_area_ds macro sizes
local clear_area_ds_cycle
; 从ds:si开始向后清理size大小的数据
    push cx
    push ax
    push si 
    push ds


    mov ax,clear_area_data
    mov ds,ax
    lea si,sizes
    mov cx,ds:[si]

    pop ax
    mov ds,ax
    pop si
    push si
    
    xor ax,ax
clear_area_ds_cycle:
    mov ds:[si],al
    inc si
    loop clear_area_ds_cycle

    pop si
    pop ax
    pop cx

endm

;================================================================

clear_area_es macro sizes
local clear_area_es_cycle
; 从es:di开始向后清理size大小的数据
    push cx
    push ax
    push di 
    push es


    mov ax,clear_area_data
    mov es,ax
    lea di,sizes
    mov cx,es:[di]

    pop ax
    mov es,ax
    pop di

    xor ax,ax
clear_area_es_cycle:
    mov es:[di],al
    inc di
    loop clear_area_es_cycle

    
    pop ax
    pop cx

endm



;================================================================

; 存放所有字符串

dispmsg macro message      ;显示字符串的宏，入参为字符串标号
    push ax
    push ds
    push si
    mov ax,strings
    mov ds,ax

    lea dx, message
    mov ah, 9

    int 21h

    pop si
    pop ax
    mov ds,ax
    pop ax
endm

;================================================================

strings segment

    Enter_string db 'Welcome to use Student Information Management System',0dh,0ah
        db 'Enter 1 to input information',0dh,0ah
        db 'Enter 2 to query information',0dh,0ah
        db 'Enter 3 to sort existing information',0dh,0ah
        db 'Enter 4 to display information',0dh,0ah
        db 'Enter 5 to display statistics',0dh,0ah
        db 'Enter 6 to export existing information',0dh,0ah
        db 'Enter 7 to import information',0dh,0ah
        db 'Enter 8 to exit',0dh,0ah,'$'


    Character_error db 'input character is unavailable, please re-enter ','$'
    Length_error db 'input character is out of range, please re-enter ','$'
    parameter_error db 'unexpect parameter, please re-enter ','$'

    inpyt_range_ db "Please enter a number between 1 ~ 8",0dh,0ah,"> ","$"

    str_to_value_parameter_error db 'input string has unavailable character ','$'
    str_to_value_mul_overflow_error db 'input string is overflow when turning to int ','$'

    Enter_name   db "Enter student's name: ",'$'
    Enter_ID db "Enter student's ID: ",'$'
    ID_range_error db 'input string has out of range, please re-enter ','$'
    score_range_error db 'input parameter is out of range(0 ~ 100), please re-enter ','$'

    Enter_score_ db " Enter student's score: ",'$'
    Enter_score_error db "Enter student's score is unavailable, please re-enter ", '$'
    Enter_course_design_score_ db "Enter student's course design score: ",'$'
    Enter_course_design_error db "Enter student's course design score is unavailable, please re-enter ",'$'


    Talbe_titles db  "=================================================================================================================================="
                db   0dh,0ah
                 db   "       <name>           <ID>         s1  s2  s3  s4  s5  s6  s7  s8  s9  s10 s11 s12 s13 s14 s15 s16    <design score>   <finial score>",'$'
    Top_Unknow_input_error_ db "Unknow_input,please re-enter",'$'

    Display_all_information_input_page db "Enter the target number of pages: ",'$'
    Display_all_information_page_left db "============================================================<page ",'$'
    Display_all_information_page_right db ">=============================================================",'$'
    


    Query_information_introduce db "Enter 1 to query by name,Enter 2 to query by ID",'$'
    Query_Finish_ db "============================================================Query Finish==========================================================",'$'
    Query_information_error_ db "Enter string is unavailable,Please re-enter","$"
    Query_information_Top_Found_ db "Found: ","$"
    Query_by_name_ db "Enter target name: ","$"
    Query_by_ID_ db "Enter target ID: ","$"

    Statistics_total_student  db "Number of Students: ","$"
    Statistics_average_score  db 0dh,0ah,"Average Score: ","$"
    Statistics_Max_score db 0dh,0ah,"Max Score: ","$"
    Statistics_Min_score db 0dh,0ah,"Min Score: ","$"

    Statistics_90to100 db 0dh,0ah,"90 ~ 100: ","$"
    Statistics_80to89 db 0dh,0ah,"80 ~ 89: ","$"
    Statistics_60to79 db 0dh,0ah,"60 ~ 79: ","$"
    Statistics_low60 db 0dh,0ah,"lower than 60: ","$"

    Sort_information_success db "Sort success",0dh,0ah,"$"
    Sort_information_no_informations_error db "There haven't informations to sort",0dh,0ah,"$"




    input_t db "> ","$"
    next_row_input_t db 0dh,0ah,"> ","$"
    to_test db 'test ','$'
    finish db 'Finish ','$'
    next_row db 0dh,0ah,'$'
    one_space db ' ','$'
    two_space db '  ','$'
    three_space db '   ','$'
    four_space db '    ','$'
    ten_space db '          ','$'

    doucument_name db   "Data",0    ;  "Data_test",0  ;
    Export_success db "Export success",0dh,0ah,"$"
    Export_error db "Export error",0dh,0ah,"$"
    Import_success db "Import success",0dh,0ah,"$"
    Import_error db "Import error",0dh,0ah,"$"


strings ends

;================================================================



; 缓存区：用于存放中间数据
cache_area segment
    cache_area_start db 80 dup(0)
cache_area ends

cache_area2 segment
    cache_area_start2 db 80 dup(0)
cache_area2 ends

; 栈区
stackmg segment stack
        db 128 dup (0)
stackmg ends



;================================================================
code segment
start:
    xor ax,ax   
    push ax     ; ss:[bp+16h]    ; 总人数
    push ax     ; ss:[bp+14h]    
    push ax     ; ss:[bp+12h]    ; 总分数   后半部分
    push ax     ; ss:[bp+10h]    ; 总分数   前半部分
    push ax     ; ss:[bp+0Eh]    ; 平均分
    push ax     ; ss:[bp+0Ch]    ; 最高分
    mov ax,0FFh
    push ax     ; ss:[bp+0Ah]    ; 最低分  默认值为FF
    mov ax,00h
    push ax     ; ss:[bp+8h]     ; 90-100 人数
    push ax     ; ss:[bp+6h]     ; 80-89 人数
    push ax     ; ss:[bp+4h]     ; 60-79 人数
    push ax     ; ss:[bp+2h]     ; 60以下人数
    push ax     ; ss:[bp]        ; 临时变量
    mov bp,sp






; 循环接收输入
; 1:录入数据
; 2:查询数据
; 3:排序数据
; 4:显示所有数据
; 5:统计数据
; 8:退出

    dispmsg Enter_string 
while_1:
    mov_dssi_to_cache_area
    clear_area_ds _1
    dispmsg inpyt_range_
    mov ax,0103h    ; 接收最大1字节的字母或数字字符
    call far ptr Get_input
    xor ah,ah
    mov al,ds:[si]
    cmp al,'1'
    jz _Enter_information_1
    cmp al,'2'
    jz _Query_information_2
    cmp al,'3'
    jz _Sort_information_3
    cmp al,'4'
    jz _Display_all_information_4
    cmp al,'5'
    jz _Statistics_information_5
    cmp al,'6'
    jz _Export_information_6
    cmp al,'7'
    jz _Import_information_7
    cmp al,'8'
    jz _exit_8
    cmp al,00h
    jz while_1
    dispmsg Top_Unknow_input_error_ 
    dispmsg next_row

    jmp while_1








_Enter_information_1:
    call far ptr Enter_information_Top
    jmp while_1

_Query_information_2:
    call far ptr Query_information_Top
    jmp while_1

_Sort_information_3:
    call far ptr Quicksort_Top
    jmp while_1

_Display_all_information_4:
    call far ptr Display_all_information_Top
    jmp while_1

_Statistics_information_5:
    call far ptr  Statistics_information
    jmp while_1

_Export_information_6:
    call far ptr Export_information
    jmp while_1

_Import_information_7:
    call far ptr Import_information
    jmp while_1


_exit_8:
    mov ax,4c00h
    int 21h









;================================================================
; 获取输入函数
Get_input proc far    
    ; 函数：获取用户输入  
    ; 参数：ds:si 录入数据的位置  al : 1 只接收数字 2 只接收字母 3 同时接收数字和字母 ah: 接收字符的长度
    ; 返回值：将录入的数据写在ds:si位置上  但是不改变si(保证不同长度输入结果si相同) al:输入字符串的长度

    ; 正常输入，将录入的数据写在ds:si位置上，只改变ax寄存器
    ; 输入超出范围，不写入数据，ax寄存器值为BADh
    ; 输入不符合要求，不写入数据，ax寄存器值为BADh


    push bp
    mov bp, sp
    push si
    push bx
    push cx
    push dx
 
    xor bx,bx   
    push bx  ;push 0
    xor cx,cx
    mov dx,si

    mov bl,al
    mov cl,ah
    add cl,1

    xor ax,ax

Get_input_cycle:
    
    mov ah, 1            ;21h-1号功能输入一个字符存入al
    int 21h 
    xor ah,ah
    cmp al, 0dh
    jz Get_input_write_Transfer    ; 接收到回车结束循环


    cmp al, 08h           ; 接收到退格键删除一个栈元素

    jnz Get_input_cycle_continue


    ; ;左方向键是4bh，右方向键是4dh，上方向键是48h，下方向键是50h
    ; cmp al,4bh
    ; jz Get_input_cycle
    ; cmp al,4dh
    ; jz Get_input_cycle
    ; cmp al,48h
    ; jz Get_input_cycle
    ; cmp al,50h
    ; jz Get_input_cycle



    pop ax                ; 出栈一个元素
    dec dx
    dec ch

    
    cmp ax,0h    
    jnz Get_input_cursor_back  ;若该元素为00，放回栈,重新进入循环,光标位置不变，若不为00，回退一格光标,

    push ax
    inc dx
    inc ch
    ; 控制光标位置不变(光标前一格为空格)
    mov ah, 0eh
	mov al, 0eh
	int 10h
	mov al, ' '
	int 10h
	mov al, 08h
	int 10h	
	mov al, 08h
	int 10h	
	mov al, ' '
	int 10h

    jmp Get_input_cycle 

Get_input_cursor_back:
    ;回退光标
    mov ah, 0eh       

	mov al, 0eh     ;防止光标移动到上一行
	int 10h
	mov al, ' '   ;写入空格
	int 10h
	mov al, 08h   ;回退光标
	int 10h	
    jmp Get_input_cycle 



Get_input_cycle_continue:
    push ax               ;输入的字符暂存在栈中
    inc dx
    inc ch

    jmp  Get_input_cycle


Get_input_write_Transfer:
    jmp Get_input_write


Get_input_unexpected_Transfer:  ; 中转
    jmp Get_input_unexpected

check_include_numbers:  ;检查输入是否为数字

    cmp al,30h
    jb Get_input_unexpected_Transfer
    cmp al,39h
    jna Get_input_write_continue
    jmp Get_input_unexpected_Transfer

check_include_letters: ;检查输入是否为字母
    cmp al,20h
    jz Get_input_write_continue
    cmp al,41h
    jb Get_input_unexpected_Transfer
    cmp al,5ah
    jna Get_input_write_continue
    cmp al,61h
    jb Get_input_unexpected_Transfer
    cmp al,7ah
    jna Get_input_write_continue
    jmp Get_input_unexpected_Transfer


check_include_numbers_and_letters:  ;检查输入是否为数字或字母
    cmp al,20h
    jz Get_input_write_continue
    cmp al,30h
    jb Get_input_unexpected_Transfer
    cmp al,39h
    jna Get_input_write_continue
    cmp al,41h
    jb Get_input_unexpected_Transfer
    cmp al,5ah
    jna Get_input_write_continue
    cmp al,61h
    jb Get_input_unexpected_Transfer
    cmp al,7ah
    jna Get_input_write_continue
    jmp Get_input_unexpected_Transfer


Get_input_write:  ; 接收完毕，开始写入数据

    sub dx,1h
    mov si,dx

    cmp ch,cl
    jae  Get_input_out_of_range  ;超过接收字符的长度限制，报错



Get_input_write_cycle:   ; 提取并检查数据
    pop ax
    cmp ax,00h
    jz Get_input_done

    cmp bx,1
    jz check_include_numbers
    cmp bx,2
    jz check_include_letters
    cmp bx,3
    jz check_include_numbers_and_letters

    dispmsg parameter_error

Get_input_write_continue:   ; 写入数据
    mov ds:[si],al
    dec si
    jmp Get_input_write_cycle


Get_input_done:
    xor ah,ah
    mov al,ch   ; 传入输入字符的长度
Get_input_done2:   ;结束  恢复寄存器
    push ax
    dispmsg next_row
    pop ax
    pop dx
    pop cx 
    pop bx
    pop si
    pop bp
    retf




Get_input_unexpected:   ; 输入发生错误
    dispmsg next_row
    dispmsg Character_error
    jmp Get_input_clear_stack

Get_input_out_of_range:  ;输入超出长度限制
    dispmsg next_row
    dispmsg Length_error 
    jmp Get_input_clear_stack

Get_input_clear_stack:  ;清除栈
    pop ax    
    cmp ax,00h
    jnz Get_input_clear_stack
    cmp dx,00h
    jz Get_input_clear_write_finish
Get_input_clear_write:  ;清除已写入数据
    mov bx,0
    mov ds:[si],bx
    dec dx
    cmp dx,0
    jnz Get_input_clear_write
Get_input_clear_write_finish:
    mov ax,0BADh
    jmp Get_input_done2





Get_input endp

    ; mov ax,data
    ; mov ds,ax
    ; lea si,data_start
    ; mov ax,0E02h    ; 接收最大14字节的字母字符串
    ; call far ptr Get_input
;================================================================
; 数据转换相关函数
Convert_str_to_value proc far    
    ; 函数：将ax位长度的字符串转换为整数
    ; 参数：ds:si 读取数据的位置 ax:要转换的的字符串的长度(1~5位) 或者到达 00 位置
    ; 返回值：将录入的数据存放在ax中 范围：(0 ~ 65535) 不改变其它寄存器的内容
    ; 错误时返回bx = 0BADh 不清除已写入内容

    
    push si
    push cx
    push dx   
    

str_to_value_start:
    mov cx,ax   ;cx存放长度
    xor ax,ax   ;ax存放结果
    xor bx,bx   ;bx存放当前数字
    xor dx,dx   ;dx置0



str_to_value_cycle:

    mov bl,ds:[si]
    cmp bx,00h  ;遇到00则提前结束
    jz str_to_value_done
    push dx
    push cx
    mov cx,0Ah
    mul cx
    cmp dx,0h
    jnz str_to_value_overflow_error ;检查乘法结果是否超过32位

    pop cx
    pop dx
    xor bh,bh

    ; 检查是否为数字ascii
    cmp bl,30h
    jb str_to_value_string_error
    cmp bl,39h
    ja str_to_value_string_error


    sub bx,30h
    add ax,bx
    inc si
    loop str_to_value_cycle
    

str_to_value_done:
    pop dx   
    pop cx
    pop si
    retf


str_to_value_overflow_error:
    pop dx
    pop cx
    dispmsg str_to_value_mul_overflow_error
    mov ax,0BADh
    jmp str_to_value_error_done

str_to_value_string_error:
    dispmsg str_to_value_parameter_error
    mov ax,0BADh
    jmp str_to_value_error_done

str_to_value_error_done:
    mov bx,0BADh
    pop dx   
    pop cx
    pop si
    retf

Convert_str_to_value endp







;================================================================



display_ax_dec proc far 
; 以10进制打印ax的值
; 参数：ax,不改变其它寄存器
; 返回值: ax 打印出字符的长度

    push bx
    push cx
    push dx
    push si
    push ds

    mov_dssi_to_cache_area

    push si
    mov dx,'$'
    push dx
 
    mov cx,0h;cx计算转换字符串的长度
    xor dx,dx

    mov bx,0ah

display_ax_dec_cycle:
    div bx
    add dx,30h
    push dx
    inc cx
    
    cmp ax,0
    jz display_ax_dec_continue

    xor dx,dx
    jmp display_ax_dec_cycle
display_ax_dec_continue:



display_ax_dec_wirte:

    pop ax
    cmp ax,'$'
    jz display_ax_dec_display
    mov ds:[si],al
    inc si
    jmp display_ax_dec_wirte




display_ax_dec_display:
    mov ds:[si],al
    pop si
    mov dx,si
    mov ah, 9
    int 21h
display_ax_dec_done:

    clear_area_ds _8

    pop ax
    mov ds,ax
    mov ax,cx
    pop si
    pop dx
    pop cx
    pop bx
    retf
display_ax_dec endp

;================================================================
; 输入信息函数

Enter_information proc far   
    ; 函数：录入数据  
    ; 参数：ds:si 录入数据的位置
    ; 返回值：将录入的数据写在ds:si位置上
    ; 输入：姓名(16字节)、学号(16字节)、16 次实验成绩(16字节)和一次课程设计成绩（1字节)


    push bp
    mov bp,sp
    push ax
    push bx
    push cx
    push dx
    push es
    push di

    push si
    push ds

; 输入姓名 最大16字节
re_Enter_name:
    dispmsg Enter_name
    mov ax,1002h    ; 接收最大16字节的字母字符串
    call far ptr Get_input
    cmp ax,0BADh
    jz re_Enter_name

    ;ss:[bp-10h] = ds
    ;ss:[bp-0Eh] = si



; 输入学号 最大16字节 存储形式为字符
re_Enter_ID:
    ; 先将输入放到缓存区，再转换为数值复制到data段
    dispmsg Enter_ID
    ; mov_dssi_to_cache_area

    ; es:di 指向data段位置
    mov ax,ss:[bp-10h]
    mov ds,ax
    mov si,ss:[bp-0Eh]
    add si,10h

    mov ax,0C01h    ; 接收最大16字节的数字字符串
    call far ptr Get_input
    cmp ax,0BADh
    jz re_Enter_ID   ;输入不符合要求，重新输入



    


;输入平时成绩  分16次输入，每次输入0~100之间的数字
Enter_usual_score:
    mov cx,10h

    xor dx,dx ;dx存放16次平时成绩的和
    push dx
    mov ax,ss:[bp-10h]
    mov es,ax
    mov di,ss:[bp-0Eh]
    add di,1Bh
    mov_dssi_to_cache_area



Enter_usual_score_cycle:
    clear_area_ds _3
    mov ax,11h
    sub ax,cx
    call far ptr display_ax_dec
    dispmsg Enter_score_

    mov ax,0301h ;接收最大3字节的数字字符串
    call far ptr Get_input
    cmp ax,0BADh
    jz Enter_usual_score_error


    mov ax,3h
    call far ptr Convert_str_to_value
    cmp bx,0BADh
    jz Enter_usual_score_error
    cmp ax,64h   ;输入的数字大于100时进行错误处理
    ja Enter_usual_score_error

    ; 写入
    add di,1h
    mov es:[di],al
    pop dx
    add dx,ax
    push dx
    ; 清理缓存区
    
    loop Enter_usual_score_cycle
    jmp Enter_usual_score_done

Enter_usual_score_error:
    dispmsg Enter_score_error
    dispmsg next_row
    jmp Enter_usual_score_cycle





Enter_usual_score_done:
    add si,012h

    ; push dx ;将16次分数的和放入栈中


    


Enter_course_design_score:
    mov ax,ss:[bp-10h]
    mov es,ax
    mov di,ss:[bp-0Eh]
    add di,2Dh

    mov ax,00h
    mov es:[di-1],al

    mov_dssi_to_cache_area
Enter_course_design_start:
    clear_area_ds _3

    dispmsg Enter_course_design_score_
    mov ax,0301h ;接收最大3字节的数字字符串
    call far ptr Get_input
    cmp ax,0BADh
    jz Enter_course_design_score_error

    mov ax,3h
    call far ptr Convert_str_to_value
    cmp bx,0BADh
    jz Enter_course_design_score_error
    cmp ax,64h   ;输入的数字大于100时进行错误处理
    ja Enter_course_design_score_error 

    mov es:[di],al
    push ax
    jmp Enter_course_design_score_done

Enter_course_design_score_error: 
    ; dispmsg Enter_course_design_error
    dispmsg next_row
    jmp Enter_course_design_start


Enter_course_design_score_done: 
    

Calculate_finial_score:
    pop bx   ; bx存放课程设计成绩
    pop ax   ; ax存放16次实验成绩之和
    ; call far ptr Calculate_finial_score

    ;finial_score = (ax * 4 + bx * 16 * 6) / 160
    
    mov cx,4h
    mul cx
    ; ax *= 4
    push ax

    ; ax = bx * 96
    mov cx,60h
    mov ax,bx
    mul cx

    pop bx
    add ax,bx

    xor dx,dx
    mov cx,0A0h
    div cx

    cmp dx,050h
    jb Calculate_finial_score_out
    add ax,1h   ;四舍五入
Calculate_finial_score_out:
    push ax
    mov ax,ss:[bp-10h]
    mov es,ax
    mov di,ss:[bp-0Eh]
    add di,2Fh
    pop ax
    mov es:[di],ax
    mov ax,00h
    mov es:[di-1],al

Enter_information_done:
    dispmsg finish
    dispmsg next_row
    pop ax
    mov ds,ax
    pop si

    pop di
    pop es
    pop dx
    pop cx
    pop bx
    pop ax
    pop bp

    retf

Enter_information endp



Enter_information_Top proc far
    ; 总学生成绩数量加1
    mov ax,ss:[bp+16h]
    inc ax
    mov ss:[bp+16h],ax
    dec ax

    ; 学生数量*2h,得到当前要写入数据的偏移地址要写入的偏移地址
    ; 学生数量*2h*18h，得到当前要写入数据的偏移地址

    mov bl,2h
    mul bl
    push ax
    mov bl,18h
    mul bl
    push ax
    ; 写入该数据的偏移地址到pointers块中

    mov ax,pointers
    mov ds,ax
    lea si,pointers_start

    mov bx,ss:[bp-6]
    mov ax,ss:[bp-8]
    mov ds:[si+bx],ax



    ; 调用Enter_information函数
    mov ax,data
    mov ds,ax
    lea si,data_start
    pop ax
    add si,ax
    call far ptr Enter_information


; 计算统计信息
Calculate_statistics:
    mov bx,2Fh
    mov ax,ds:[si+bx] ;取最终成绩到ax中
    push ax

statistics_max: 
    mov dx,ss:[bp+0Ch]
    cmp ax,dx    ;是否超过原最高分
    jna statistics_min

    mov ss:[bp+0Ch],ax
statistics_min:
    mov dx,ss:[bp+0Ah]
    cmp ax,dx    ;是否低于原最低分
    jnb statistics_90_to_100

    mov ss:[bp+0Ah],ax
statistics_90_to_100:
    cmp ax,5Ah      ;是否大于90分
    jb statistics_80_to_89
    mov bx,ss:[bp+8h]
    inc bx
    mov ss:[bp+8h],bx
    jmp Calculate_average

statistics_80_to_89:
    cmp ax,50h       ;是否大于80分
    jb statistics_60_to_79
    mov bx,ss:[bp+6h]
    inc bx
    mov ss:[bp+6h],bx
    jmp Calculate_average

statistics_60_to_79:
    cmp ax,3Ch       ;是否大于60分
    jb statistics_lower_than_60
    mov bx,ss:[bp+4h]
    inc bx
    mov ss:[bp+4h],bx
    jmp Calculate_average

statistics_lower_than_60:
    mov bx,ss:[bp+2h]
    inc bx
    mov ss:[bp+2h],bx







; 计算平均成绩
Calculate_average:
    mov ax,ss:[bp+10h]    ; 获取原总分数
    mov dx,ss:[bp+12h]    

    pop bx
    add ax,bx
    adc dx,0

    mov  ss:[bp+10h],ax    ;写入新总分数s
    mov  ss:[bp+12h],dx

    mov bx,ss:[bp+16h]
    div bx  ;总平均分 = 所有学生平均分相加 / 总人数

    mov ss:[bp+0Eh],ax




    add sp,2h
    retf
Enter_information_Top endp
;================================================================
; 查询信息函数

Query_information proc far
; 函数：根据es:di              查询data段中的信息并显示
; 参数: ah = 1: 按名字查询  ah = 2: 按学号查询   al: 查询的字符串的长度 es:ip :查询的字符串的存放地址
; 返回：ax保存查询到的数据数量

    push bx
    push cx
    push dx

    push ax
    mov ax,ss:[bp+16h]

    mov cx,ax   ; cx表示当前有多少条信息
    pop ax
    cmp cx,00h   ; 无信息直接退出
    jz Query_information_finish  

    xor dh,dh
    mov dl,al   ; dx存放字符串长度

    cmp ah,01h
    jz Query_information_name
    cmp ah,02h
    jz Query_information_ID
    jmp Query_information_error

Query_information_name:
    mov bx,00h
    jmp Query_information_start  ;按名字查询 
Query_information_ID:
    mov bx,10h
    jmp Query_information_start  ;按学号查询


Query_information_start:
    mov ax,data
    mov ds,ax
    mov ax,0h
Query_information_cycle:
    push ax
    call far ptr Get_pointers   ;获取偏移地址
    cmp ax,0BADh
    jz Query_information_finish

    mov si,ax
    add si,bx
    mov ax,dx
    call far ptr Kmp ; check_equal   ; 

    cmp ax,1h  ;查询到相等字符串,直接打印
    jnz Query_information_continue
    sub si,bx
    call far ptr Display_one_information

    mov ax,ss:[bp]   ;总查询到的信息地址存储在ss:[bp]上
    add ax,1h
    mov ss:[bp],ax

Query_information_continue:

    pop ax
    inc ax
    cmp ax,cx
    jz Query_information_finish

    jmp Query_information_cycle





Query_information_finish:
    pop dx
    pop cx
    pop bx
    retf

Query_information_error:
    pop dx
    pop cx
    pop bx
    retf

Query_information endp


;================================================================


Query_information_Top proc far

Query_information_Top_start:
    dispmsg Query_information_introduce
    dispmsg next_row
    dispmsg input_t
    mov_dssi_to_cache_area2
    mov ax,0101h    ; 接收最大1字节的数字字符
    call far ptr Get_input
    xor ah,ah
    mov al,ds:[si]
    clear_area_ds _1
    cmp al,'1'
    jz Query_information_query_by_name
    cmp al,'2'
    jz Query_information_query_by_ID_Transfer

    jmp Query_information_Top_error

Query_information_Top_error_Transfer:
    jmp  Query_information_Top_error
Query_information_query_by_ID_Transfer:
    jmp  Query_information_query_by_ID


Query_information_query_by_name:
    dispmsg Query_by_name_ 
    dispmsg next_row_input_t
    mov_dssi_to_cache_area2
    mov ax,0E02h    ; 接收最大14字节的字母字符串
    call far ptr Get_input
    cmp ax,0BADh
    jz Query_information_Top_error_Transfer
    push ax
    dispmsg Talbe_titles
    dispmsg next_row 

    mov_esdi_to_cache_area2
    pop ax
    mov ah,01h
    mov al,10h
    call far ptr Query_information
    jmp Query_information_Top_finish





Query_information_query_by_ID:
    dispmsg Query_by_ID_
    dispmsg next_row_input_t
    mov_dssi_to_cache_area2
    mov ax,0C01h    ; 接收最大12字节的数字字符串
    call far ptr Get_input
    cmp ax,0BADh
    jz Query_information_Top_error
    push ax
    dispmsg Talbe_titles
    dispmsg next_row 

    mov_esdi_to_cache_area2
    pop ax
    mov ah,02h
    mov al,0Ch
    call far ptr Query_information
    jmp Query_information_Top_finish



Query_information_Top_error:
    dispmsg next_row
    jmp Query_information_Top_start

Query_information_Top_finish:
    dispmsg Query_Finish_
    dispmsg next_row
    mov_esdi_to_cache_area2
    clear_area_es _80

    mov ax,ss:[bp]
    mov bx,0h
    mov ss:[bp],bx
    dispmsg Query_information_Top_Found_ 
    call far ptr display_ax_dec
    dispmsg next_row


    retf
Query_information_Top endp


;================================================================
; 输出信息函数


Display_one_information proc far   
; 函数：打印单个学生的成绩数据
; 参数：ds:si 要打印数据的位置
; 无返回
; 打印格式：  name(14byte) (spaces*2) ID(12byte) (spaces*2) (score + space)*16 (sapce * 2) (course design score) (space *2) (finial score)
    
    push bp
    mov bp,sp
    push ds
    push si
    push ax
    push bx
    push cx
    push dx
    push es
    push di



    dispmsg one_space
    ; 将转换的字符暂时写在缓存区中
    mov_esdi_to_cache_area
    mov dx,20h ; dx存储空格字符

    ; 写入学生姓名

    mov cx,10h
    xor bx,bx
Display_one_information_name_cycle:
    mov al,ds:[si+bx]
    mov es:[di+bx],al
    inc bx
    loop Display_one_information_name_cycle
    

;写入空格
    xor bx,bx
Display_one_information_name_write_space:
    inc bx
    cmp bx,12h
    ja Display_one_information_ID
    mov ax,es:[di+bx]
    cmp ax,00h
    jnz Display_one_information_name_write_space
    mov es:[di+bx],dl
    jmp Display_one_information_name_write_space





Display_one_information_ID:
    ; 写入学生学号
    add si,010h
    mov di,012h
    mov cx,0Ch
    xor bx,bx
Display_one_information_ID_cycle:
    mov al,ds:[si+bx]
    mov es:[di+bx],al
    inc bx
    loop Display_one_information_ID_cycle

;写入空格
    xor bx,bx
Display_one_information_ID_write_space:
    inc bx
    cmp bx,0Ch
    ja Display_one_information_ID_done
    mov ax,es:[di+bx]
    cmp ax,00h
    jnz Display_one_information_ID_write_space
    mov es:[di+bx],dl
    jmp Display_one_information_ID_write_space


Display_one_information_ID_done:
    mov dl,'$'
    mov es:[di+bx],dl


    ; 输出 姓名和学号
    mov_dssi_to_cache_area
    mov dx,si
    mov ah, 9
    int 21h
    ; 清除缓存
    clear_area_ds _48 



    ;输出分数
    mov ax,ss:[bp-2]
    mov ds,ax
    mov si,ss:[bp-4]
    add si,1Ch

    mov cx,10h
    xor bx,bx
Display_one_information_score_cycle:
    push cx
    xor ax,ax
    mov al,ds:[si+bx]
    inc bx
    call far ptr display_ax_dec
    mov cx,4h
    sub cx,ax
Display_one_information_score_display_space:
    dispmsg one_space
    loop Display_one_information_score_display_space
    pop cx
    loop Display_one_information_score_cycle

    dispmsg ten_space
    xor ax,ax
    add bx,1h
    mov al,ds:[si+bx]
    call far ptr display_ax_dec

    dispmsg ten_space
    dispmsg four_space

    xor ax,ax
    add bx,2h
    mov al,ds:[si+bx]
    call far ptr display_ax_dec

    dispmsg next_row
    pop di
    pop ax
    mov es,ax
    pop dx
    pop cx
    pop bx
    pop ax
    pop si
    pop ax
    mov ds,ax
    pop bp
    retf

Display_one_information endp


;================================================================

Display_all_information proc far   
    dispmsg Talbe_titles
    dispmsg next_row 
; 函数： 打印出data段中所有的学生信息
; 参数 ax 页数 第一页为0,每页显示20行信息
    push ax
    mov ax,ss:[bp+16h]
    mov dx,ax   ; dx表示当前有多少条信息

    pop ax
    push ax
    mov bl,14h
    mul bl     ; ax表示从第几条信息开始打印
    mov bx,ax
    cmp ax,dx
    ja Display_all_information_done  ;开始打印位置大于信息数量，直接结束程序

    mov ax,data
    mov ds,ax
    lea si,data_start


    mov cx,14h

    ; bx: 起始地址
    



Display_all_information_cycle:



    mov ax,bx
    call far ptr Get_pointers
    mov si,ax
    cmp bx,dx   ;  bx超过dx时退出
    jnb Display_all_information_done

    cmp cx,0h   ; 输出超过20条时退出
    jz Display_all_information_done

    push dx
    push cx
    push bx
    push ax
    mov ax,bx   ;输出排名
    inc ax
    call far ptr display_ax_dec

    mov cx,5h
    sub cx,ax
Display_space:
    dispmsg one_space 
    loop Display_space
    pop ax
    pop bx  
    pop cx
    pop dx


    call far ptr Display_one_information

    dec cx
    add bx,1
    jmp Display_all_information_cycle


Display_all_information_done:

    dispmsg Display_all_information_page_left
    pop ax
    inc ax
    call far ptr display_ax_dec
    dispmsg Display_all_information_page_right
    dispmsg next_row
    retf


Display_all_information endp


;================================================================

Display_all_information_Top proc far  

    dispmsg Display_all_information_input_page

    mov_dssi_to_cache_area
    clear_area_ds _2
    mov ax,0201h    ; 接收最大1字节的数字字符
    call far ptr Get_input
    xor ah,ah
    mov al,ds:[si]
    ; 将输入的字符串转换为数值
    mov ax,2h
    call far ptr Convert_str_to_value 
    ; 以该数值为参数调用Display_all_information
    dec ax
    call far ptr Display_all_information
    mov_dssi_to_cache_area
    clear_area_ds _2  

    retf
Display_all_information_Top endp

;================================================================
; 排序信息函数


; data segment
;     dw  142,999,1212,664,235,246,235,100,783,315,435,123;,1,5,3,4,9;,6;,8,9,10,11,12,13,14,15,16,17
; data ends

; stackmg segment stack
;     stackmg_stack dw 300 dup(0)  ;1 * 1000 
; stackmg ends

; pointers segment
;     pointers_start   dw 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
; pointers ends


Quicksort_Top proc far
; 函数：调用快速排序函数按成绩排序学生信息

    mov ax,data

    ; mov ax,0h
    ; mov bx,1h
    ; call far ptr Compare_ax_bx


    mov ax,ss:[bp+16h]  ;总人数
    cmp ax,0h
    jz Quicksort_Top_error_no_informations
    dec ax
    push ax
    lea ax,data_start
    push ax
    call far ptr Quicksort
    add sp,4h

    dispmsg Sort_information_success

    retf
Quicksort_Top_error_no_informations:
    dispmsg Sort_information_no_informations_error
    retf





Quicksort_Top endp

;================================================================

Quicksort proc far
; 函数：快速排序算法
; 参数: 存放在栈中
; sort_l = ss:[bp+6]
; sort_r = ss:[bp+8]
    push bp    
    mov bp,sp
    ; addr = ss:[bp-2]
    ; value = ss:[bp-4]
    xor ax,ax
    push ax
    push ax

    push ax
    push bx
    push cx
    push dx
    push si
    push ds


    
    mov ax,ss:[bp+6]
    cmp ax,ss:[bp+8]
    jnb  Quicksort_done       ;l>=r return
    ; l<r 继续
Quicksort_continue:

    mov dx,pointers
    mov ds,dx

    mov bx,ss:[bp+6]

    xor bx, bx      
    mov si,ss:[bp+6]    ;i=l
    mov bx,ss:[bp+8]    ;j=r
         ; l*=2 以字为单位

    ; mov ax, ds:[si]     ;用ax保存base = pointers[l]
    mov ax,si
    mov ss:[bp-2], si
    mov ss:[bp-4], ax  
    inc si               ;i+=1

    cmp si,bx 
    jnb Quicksort_find_j_above_base
    jmp Quicksort_cycle

;结束函数
Quicksort_done:
    pop ax
    mov ds,ax
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    add sp,4h
    pop bp
    retf


; 循环
Quicksort_cycle:
    cmp si,bx      ;while (i!=j)  / i<j
    jnb Quicksort_over_cycle   ; i=j  跳出循环
        
Quicksort_find_j_above_base:
    call  far ptr Compare_ax_bx
    cmp  dx,2h      ; ax < bx    x<j
    jz Quicksort_found_j
    cmp si,bx
    jnb Quicksort_over_cycle ; i>=j 跳出循环
    dec bx ; j-=1
    jmp Quicksort_find_j_above_base
Quicksort_found_j:

    push si
    push bx
    push bx

    mov ss:[bp-2], bx

    mov dx,bx
    mov si,ax
    shl si,1h
    shl bx,1h

    mov cx,ds:[si]
    mov dx,ds:[bx]
    mov ds:[bx],cx
    mov ds:[si],dx



    pop ax
    pop bx
    pop si

Quicksort_find_i_below_base:

    call far ptr Compare_ax_si
    cmp  dx,3h       ; ax > si   x>i
    jz Quicksort_found_i
    cmp si,bx 
    jnb Quicksort_over_cycle  ; i>=j 跳出循环
    inc si   ; i+=1
    jmp Quicksort_find_i_below_base


Quicksort_found_i:


    push si
    push bx
    push si

    mov ss:[bp-2], si

    mov dx,si
    mov bx,ax
    shl bx,1h
    shl si,1h

    mov cx,ds:[bx]
    mov dx,ds:[si]
    mov ds:[si],cx
    mov ds:[bx],dx



    pop ax
    pop bx
    pop si

    jmp Quicksort_cycle



Quicksort_over_cycle:

    mov ax,ss:[bp+6]
    mov cx,ss:[bp+8]
    ;

    ; mov es,si
    ; jmp Quicksort_done
    mov si,ss:[bp-2]
    ; shr si,1h


Quicksort_recursion1:
    push si                 ; si = i
    dec si                  ; i-=1

    cmp si,ss:[bp+6]
    jle Quicksort_recursion2 ; i <= left 时不进行递归

    push si                 ;push i-1
    push ss:[bp+6]          ;push l
    call Quicksort        ;quicksort(l, i-1);
    add sp,4h

Quicksort_recursion2:
    pop si                   ; 复原i
    inc si

    cmp si,ss:[bp+8]
    jnl Quicksort_done_tranfer  ; i >= right 时不进行递归

    push ss:[bp+8]          ;push r
    push si                 ;push i+1
    call Quicksort          ;quicksort(i+1, r);
    add sp,4h
Quicksort_done_tranfer:
    jmp Quicksort_done



Quicksort endp


;================================================================

Compare_ax_si proc far
; 函数：比较data[pointer[ax]]和data[pointer[si]]的大小，返回值在dx上
    push ax
    push bx
    push cx
    push si
    push ds
    push ax
    push si


    mov ax,pointers
    mov ds,ax
    pop bx
    shl bx,1h
    mov ax,ds:[bx]


    mov dx,data
    mov ds,dx
    mov si,ax
    mov cl,ds:[si+2Fh]   ;cx = data[si]
    xor ch,ch

    mov ax,pointers
    mov ds,ax
    pop bx
    shl bx,1h
    mov ax,ds:[bx]

    mov dx,data
    mov ds,dx
    mov si,ax
    mov dl,ds:[si+2Fh]   ;dx = data[ax]
    xor dh,dh

    cmp dx,cx
    ja Compare_ax_si_above
    jb Compare_ax_si_below

Compare_ax_si_equal:
    mov dx,1h
    jmp Compare_ax_si_done
Compare_ax_si_below:
    mov dx,2h
    jmp Compare_ax_si_done
Compare_ax_si_above:
    mov dx,3h

Compare_ax_si_done:
    pop ax
    mov ds,ax
    pop si
    pop cx
    pop bx
    pop ax
    retf
Compare_ax_si  endp
;=================================================
Compare_ax_bx proc far
; 函数：比较data[ax]和data[bx]的大小，返回值在dx上
    push ax
    push cx
    push bx
    push si
    push ds
    push ax
    push bx


    mov ax,pointers
    mov ds,ax
    pop bx
    shl bx,1h
    mov ax,ds:[bx]


    mov dx,data
    mov ds,dx
    mov si,ax
    mov cl,ds:[si+2Fh]   ;cx = data[bx]
    xor ch,ch

    mov ax,pointers
    mov ds,ax
    pop bx
    shl bx,1h
    mov ax,ds:[bx]

    mov dx,data
    mov ds,dx
    mov si,ax
    mov dl,ds:[si+2Fh]   ;dx = data[ax]
    xor dh,dh

    cmp dx,cx
    ja Compare_ax_bx_above
    jb Compare_ax_bx_below

Compare_ax_bx_equal:
    mov dx,1h
    jmp Compare_ax_bx_done
Compare_ax_bx_below:
    mov dx,2h
    jmp Compare_ax_bx_done
Compare_ax_bx_above:
    mov dx,3h

Compare_ax_bx_done:    
    pop ax
    mov ds,ax
    pop si
    pop bx
    pop cx
    pop ax
    retf


Compare_ax_bx endp







;================================================================
; 导入导出数据函数


Export_information proc far
    ;函数: 导出数据
    ;无参数，无返回值

    ; 创建文件，返回句柄
    mov ax,strings
    mov ds,ax
    lea dx,doucument_name
    mov ah,3ch
    mov cx,00h
    int 21h
    jc Export_information_error_tranfer;判断是否出错
    push ax
    ; 文件句柄 = ss:[bp-6]

    

    ; 写入统计数据:  ss:[bp] 到 ss:[bp+16]
    mov ax,ss
    mov ds,ax
    mov dx,bp
    mov ah,40h
    mov cl,18h
    mov bx,ss:[bp-6]      ;取出文件句柄
    
    int 21h
    jc Export_information_error_tranfer

    ; 写入空格
    mov_dssi_to_cache_area
    clear_area_ds _8
    mov ah,40h
    mov cl,18h
    mov dx,si
    mov bx,ss:[bp-6]      ;取出文件句柄

    int 21h

    jmp Write_data


Export_information_error_tranfer:   
    jmp Export_information_error




Write_data:
    ; 写入学生数据
    ; ds指向data段
    mov ax,data
    mov ds,ax
    ; 获取学生人数
    mov cx,ss:[bp+16h]
    cmp cx,0h
    jz Export_information_error   ; 无数据时输出error

    mov ax,0h

Export_information_loop:
    push cx
    push ax

    ; 获取数据偏移地址
    call far ptr Get_pointers 
    mov dx,ax

    mov ah,40h
    mov cl,30h            ;一个学生信息为48字节
    mov bx,ss:[bp-6]      ;取出文件句柄
    int 21h

    pop ax
    pop cx
    inc ax
    loop Export_information_loop

Export_information_success:
    ;移动文件指针
    xor cx,cx
    xor dx,dx
    mov bx,ss:[bp-6]   
    mov al,0    
    mov ah,42h
    int 21h
    jc Export_information_error
    dispmsg Export_success

    pop ax
    retf

Export_information_error:
    dispmsg Export_error

    pop ax
    retf

Export_information endp

;==================================================================


Import_information  proc far
    ;函数: 导入数据
    ;无参数，无返回值




    ;打开文件，返回句柄
    mov ax,strings
    mov ds,ax
    lea dx,doucument_name
    mov ah,3dh
    mov al,0h  ;只读
    mov cx,00h
    int 21h
    jc Import_information_error_tranfer;判断是否出错
    push ax
    ; 文件句柄 = ss:[bp-4]
    jmp Write_statistics

Import_information_error_tranfer:
    jmp Import_information_error




Write_statistics:
    ;读取统计信息

    mov ax,ss
    mov ds,ax
    mov dx,bp

    mov ah,3fh
    mov bx,ss:[bp-6]
    mov cx,18h;读前24个 (统计信息)

    int 21h
    jc Import_information_error
    

    
;移动文件指针
    mov dx,30h
    xor cx,cx
    mov bx,ss:[bp-6]
    mov al,0    
    mov ah,42h
    int 21h
    jc Import_information_error


    mov cx,ss:[bp+16h]

    ;读取学生数据
    mov ax,data
    mov ds,ax


    lea dx,data_start

Write_data_loop:
    push cx
    mov ah,3fh
    mov bx,ss:[bp-6]
    mov cx,30h
    int 21h

    pop cx
    add dx,30h
    loop Write_data_loop









    ;重新设置指针

    ; 获取学生人数
    mov cx,ss:[bp+16h]

    mov ax,pointers
    mov ds,ax
    lea si,pointers_start
    mov ax,0h
Write_pointers_loop:
    mov ds:[si],ax
    add ax,30h
    add si,2h
    loop Write_pointers_loop

    dispmsg Import_success

    pop ax
    retf




Import_information_error:
    dispmsg Import_error


    pop ax
    retf



Import_information endp
;================================================================

; 显示统计信息函数

Statistics_information proc far
    
    dispmsg Statistics_total_student
    mov ax,ss:[bp+16h]
    call far ptr display_ax_dec

    dispmsg Statistics_average_score
    mov ax,ss:[bp+0Eh]
    call far ptr display_ax_dec

    dispmsg Statistics_Max_score
    mov ax,ss:[bp+0Ch]
    call far ptr display_ax_dec

    dispmsg Statistics_Min_score
    mov ax,ss:[bp+0Ah]
    call far ptr display_ax_dec

    dispmsg Statistics_90to100
    mov ax,ss:[bp+8h]
    call far ptr display_ax_dec

    dispmsg Statistics_80to89
    mov ax,ss:[bp+6h]
    call far ptr display_ax_dec

    dispmsg statistics_60to79
    mov ax,ss:[bp+4h]
    call far ptr display_ax_dec

    dispmsg Statistics_low60
    mov ax,ss:[bp+2h]
    call far ptr display_ax_dec

    dispmsg next_row

    retf

Statistics_information endp

;================================================================
; 其它函数
;================================================================


check_equal proc far   
; 函数 检查两段数据是否完全相等
; 参数：ax 要检查数据的长度  ds:si es:di 两段数据所在地址
; 返回: ax = 1 相等  ax =0 不相等
    push bx
    push cx
    push dx

    mov cx,ax
    xor bx,bx
check_equal_cycle:
    mov al,ds:[si+bx]
    mov dl,es:[di+bx]
    cmp al,dl
    jnz check_equal_false
    inc bx
    loop check_equal_cycle
    jmp check_equal_true


check_equal_true:
    mov ax,1h
    pop dx
    pop cx
    pop bx
    retf


check_equal_false:
    mov ax,0h
    pop dx
    pop cx
    pop bx
    retf
check_equal endp

Kmp proc far
; KMP算法比较两字符串是否相等
; 参数: ds:si  es:di  两字符串位置(预留80字节空间 子字符串长度要小于40,next数组保存在es:[di+40]上)  ax 最大匹配字符串长度


    push bx
    push cx
    push dx

    push ds
    push si
    push es
    push di

    push ax ; ss:[bp+2] 最大匹配字符串长度

    mov cx,ds
    mov dx,si
    mov ax,es
    mov ds,ax
    mov si,di   ; ds:si <= es:di

    call far ptr build_next

    mov ds,cx
    mov si,dx

    push bp
    mov bp,sp

    xor ax,ax
    push ax  ; ss:[bp-2]    i = 0 主串指针   ds:[si+bx]
    push ax  ; ss:[bp-4]    j = 0 子串指针   es:[di+bx]

    xor ah,ah 
    xor bh,bh
    xor ch,ch
    xor dh,dh

Kmp_loop:
    ; i = len(str) false
    mov bl,ss:[bp-2]
    mov al,ds:[si+bx]
    cmp al,0h
    jz Kmp_return_false
    mov al,ss:[bp-2]
    mov bl,ss:[bp+2]
    cmp al,bl   ; j >= max_len 结束
    jnl Kmp_return_false

    mov bl,ss:[bp-2]
    mov cl,ds:[si+bx]
    mov bl,ss:[bp-4]
    mov dl,es:[di+bx]
    cmp cl,dl
    jnz Kmp_loop_continue1

    mov al,ss:[bp-2]
    inc al
    mov ss:[bp-2],al   ;i+=1

    mov al,ss:[bp-4]
    inc al
    mov ss:[bp-4],al   ;j+=1

    jmp Kmp_loop_continue3

Kmp_loop_continue1:
    mov bl,ss:[bp-4]
    cmp bl,0
    jle Kmp_loop_continue2

    ; j = next[j-1]


    mov bl,ss:[bp-4]
    dec bl
    mov al,es:[di+bx+28h]  ;从next表中取数据,写入j
    mov ss:[bp-4],al
    jmp Kmp_loop_continue3

Kmp_loop_continue2:
    mov al,ss:[bp-2]
    inc al
    mov ss:[bp-2],al   ; i+=1
    ; jmp Kmp_loop_continue3


Kmp_loop_continue3:
    ; j =len(patt) true
    mov bl,ss:[bp-4]
    mov ax,es:[di+bx]
    cmp al,0h
    jz Kmp_return_true
    jmp Kmp_loop



Kmp_return_false:
    add sp,4h
    pop bp
    mov ax,0h
    add sp,2h  

    pop di
    pop ax
    mov es,ax
    pop si
    pop ax
    mov ds,ax

    pop dx
    pop cx
    pop bx

    retf

Kmp_return_true:
    add sp,4h
    pop bp
    mov ax,1h
    add sp,2h  

    pop di
    pop bx
    mov es,bx
    pop si
    pop bx
    mov ds,bx

    pop dx
    pop cx
    pop bx

    retf





Kmp endp


build_next proc far
; 生成next数组
; 参数: ds:si
; 结果保存在 ds:[si+28h]中
    push ax
    push bx
    push cx
    push dx

    push ds
    push si

    push es
    push di







    push bp
    mov bp,sp
    mov ax,1h
    push ax   ; ss:[bp-2]     i = 0  （由于next数组的首）
    xor ax,ax
    push ax   ; ss:[bp-4]     当前共同前后缀长度 prelen= 0
    mov ax,1h    
    push ax   ; ss:[bp-6]     next数组的长度(从1开始) len = 1
 


    mov ax,ds
    mov es,ax
    mov di,si
    add di,28h    ; es:di 为next数组地址


    xor ax,ax
    mov es:[di],al    ; next[0] = 0

    ; mov cx,0h       
    ; mov dx,0h      
    xor ah,ah 
    xor bh,bh
    xor ch,ch
    xor dh,dh

build_next_loop:

    mov bl,ss:[bp-2]

    mov al,ds:[si+bx]
    cmp al,00h     ; 取到字符串末尾，结束循环
    jz build_next_done

    mov bl,ss:[bp-2]
    mov cl,ds:[si+bx]
    mov bl,ss:[bp-4]
    mov dl,ds:[si+bx]

    cmp cl,dl   ; str[prelen] = str[i]
    jnz build_next_continue1

    mov al,ss:[bp-4]  
    inc al
    mov ss:[bp-4],al   ;prelen+=1


    mov bl,ss:[bp-6]
    mov es:[di+bx],al
    inc bl
    mov ss:[bp-6],bl   ;len+=1

    mov al,ss:[bp-2]  
    inc al
    mov ss:[bp-2],al   ;i+=1

    jmp build_next_loop

build_next_continue1:
    mov al,ss:[bp-4]
    cmp al,00h
    jnz build_next_continue2

    mov bl,ss:[bp-6]
    mov es:[di+bx],al
    inc bl
    mov ss:[bp-6],bl   ;len+=1

    mov al,ss:[bp-2]  
    inc al
    mov ss:[bp-2],al   ;i+=1



    jmp build_next_loop

build_next_continue2:

    mov bx,ss:[bp-4]
    dec bl
    mov al,es:[di+bx]
    mov ss:[bp-4],ax


    jmp build_next_loop






build_next_done:

    add sp,6h
    pop bp

    pop di
    pop ax
    mov es,ax

    pop si
    pop ax
    mov ds,ax

    pop dx
    pop cx
    pop bx
    pop ax

    ret

build_next endp
;================================================================

Get_pointers  proc far  
; 函数：从pointers段获取目标地址
; 参数：ax: 要查询第几个地址 
; 返回：ax: 目标偏移地址 若查询的地址位置大于总地址数，返回ax = BADh

    

    push dx
    push ds
    push si
    push bx


    mov bx,ss:[bp+16h]
    cmp ax,bx
    jnb Get_pointers_error



    mov bl,2h
    mul bl
    mov bx,ax
    mov ax,pointers
    mov ds,ax
    lea si,pointers_start

    mov dx,ds:[si+bx]

    pop bx
    pop si
    pop ax
    mov ds,ax

    mov ax,dx
    pop dx


    retf
Get_pointers_error:
    pop bx
    pop si
    pop ax
    mov ds,ax

    mov ax,0BADh
    pop dx
    



    retf
Get_pointers endp

;================================================================

code ends
end start



